package com.tbit.uqbike.service.business.operationsanalysis.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.tbit.common.entity.pojo.dto.BarChartDispatchLogDTO;
import com.tbit.common.entity.pojo.dto.BarChartRepairDTO;
import com.tbit.common.entity.pojo.vo.DateResult;
import com.tbit.uqbike.manager.exception.BaseException;
import com.tbit.uqbike.object.pojo.Region;
import com.tbit.uqbike.object.pojo.dto.WorkOrderLogQueryDTO;
import com.tbit.common.entity.pojo.vo.CoreDataVO;
import com.tbit.common.entity.pojo.vo.LineChartVO;
import com.tbit.uqbike.object.pojo.vo.MachineLineChartVO;
import com.tbit.common.entity.view.Result;
import com.tbit.uqbike.service.business.MoveLogService;
import com.tbit.uqbike.service.business.PowerChangeLogService;
import com.tbit.uqbike.service.business.operationsanalysis.MaintainOAService;
import com.tbit.uqbike.webmanager.dao.log.DispatchLogDao;
import com.tbit.uqbike.webmanager.dao.log.FaultReportDao;
import com.tbit.uqbike.webmanager.dao.log.PowerChangeLogDao;
import com.tbit.uqbike.webmanager.dao.log.RepairLogDao;
import com.tbit.uqbike.webmanager.dao.stat.MachineOperationsStatDao;
import com.tbit.utils.DateTimeUtil;
import com.tbit.utils.NullUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 运维分析Service接口实现
 *
 * @author <a href="mailto:chen.wutian@tbit.com.cn">BUGTian</a>
 * @since 2025/2/27
 */
@Service
public class MaintainOAServiceImpl implements MaintainOAService {

    @Resource
    private PowerChangeLogService powerChangeLogService;
    @Resource
    private MoveLogService moveLogService;
    @Resource
    private RepairLogDao repairLogDao;
    @Resource
    private DispatchLogDao dispatchLogDao;
    @Resource
    private FaultReportDao faultReportDao;
    @Resource
    private MachineOperationsStatDao machineOperationsStatDao;
    @Resource
    private PowerChangeLogDao powerChangeLogDao;


    /**
     * 获取运维分析核心数据
     *
     * @param accountId 区域id
     * @param startDate 开始日期
     * @param endDate   结束日期
     * @return Result<CoreDataVO>
     */
    @Override
    public Result<CoreDataVO> getMainCoreData(Integer accountId, Date startDate, Date endDate) {
        /*换电*/
        WorkOrderLogQueryDTO workOrderLogQueryDTO = new WorkOrderLogQueryDTO().
                setAccountId(accountId)
                .setStartTime(startDate.getTime())
                .setEndTime(endDate.getTime());
        Integer batterySwapCount = powerChangeLogService.queryCount(workOrderLogQueryDTO);
        /*调度*/
        Integer dispatchCount = dispatchLogDao.getAllDispatchCount(accountId, startDate, endDate);
        /*挪车*/
        Integer moveCount = moveLogService.queryCount(accountId, null, null, null, startDate.getTime(), endDate.getTime());
        /*维修*/
        Integer repairCount = repairLogDao.getAllRepairCount(accountId, startDate, endDate);

        return Result.success(new CoreDataVO(batterySwapCount, dispatchCount, moveCount, repairCount));
    }


    /**
     * 获取运维分析维修故障折线图数据
     *
     * @param accountId 区域id
     * @param startDate 开始日期
     * @param endDate   结束日期
     * @return Result<LineChartVO>
     */
    @Override
    public Result<List<LineChartVO>> getMachineFaultLineChart(Integer accountId, Date startDate, Date endDate) {
        List<LineChartVO> lineChartVOList = faultReportDao.getMachineFaultLineChart(accountId, startDate, endDate);
        Map<String, Integer> dataMap = lineChartVOList.stream().collect(Collectors.toMap(LineChartVO::getDate, LineChartVO::getCount));
        //获取传入时间每天的日期
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        List<String> findTimeList = DateTimeUtil.findDaysStr(simpleDateFormat.format(startDate), simpleDateFormat.format(endDate));

        /*处理数据，没有数据进行补0操作*/
        List<LineChartVO> lineChartData = new ArrayList<>();
        findTimeList.forEach(date -> lineChartData.add(new LineChartVO(date, dataMap.getOrDefault(date, 0))));

        return Result.success(lineChartData);
    }


    /**
     * 运营分析-运维分析数据-车辆数据分时折线图
     *
     * @param accountId 区域id
     * @param startDate 开始时间
     * @param endDate   结束时间
     * @param type      数据类型：1-低电分时 2-超区分时 3-超时分时
     * @return Result<List < LineChartVO>>
     */
    @Override
    public Result<List<LineChartVO>> getMachineLineChart(Integer accountId, Date startDate, Date endDate, Integer type) {

        //构造返回数据
        List<LineChartVO> lineChartVOList = new ArrayList<>();

        /*单天*/
        if (isSameDay(startDate, endDate)) {
            List<MachineLineChartVO> machineLineChartVOList = machineOperationsStatDao.selectMachineLineChart(accountId, DateTimeUtil.formatDateYMD(startDate));
            processHourlyData(machineLineChartVOList, getHour(startDate, endDate), type, lineChartVOList);
        }else {
            /*获取每一天的日期*/
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
            List<String> findTimeList = DateTimeUtil.findDaysStr(simpleDateFormat.format(startDate), simpleDateFormat.format(endDate));
            /*多天*/
            List<MachineLineChartVO> machineLineChartVOList = machineOperationsStatDao.selectMachineLineChartByDay(accountId, DateTimeUtil.formatDateYMD(startDate), DateTimeUtil.formatDateYMD(endDate));
            processDailyData(machineLineChartVOList, findTimeList, type, lineChartVOList);
        }
        return Result.success(lineChartVOList);
    }


    /**
     * 运维分析-换电分析
     * @param accountId 区域id
     * @param startDate 开始时间
     * @param endDate   结束时间
     * @return Result<List<DateResult>>
     */
    @Override
    public Result<List<DateResult>> getPowerAnalyze(Integer accountId, Date startDate, Date endDate) {
        Map<String, Object> map = new HashMap<>();
        map.put("accountId", accountId);
        map.put("startTime", startDate);
        map.put("endTime", endDate);
        List<DateResult> results = powerChangeLogDao.statisticsByTime(map);
        /**获取查询数据的日期集合*/
        List<String> dateList = results.stream().map(DateResult::getDate).collect(Collectors.toList());
        /**获取传入时间每天的日期*/
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        List<String> findTimeList = DateTimeUtil.findDaysStr(simpleDateFormat.format(startDate), simpleDateFormat.format(endDate));
        /**得到传入时间和查询数据日期集合的差集*/
        List<String> reduce = findTimeList.stream().filter(item -> !dateList.contains(item)).collect(Collectors.toList());
        /**进行补0*/
        if (CollectionUtil.isNotEmpty(reduce)) {
            for (String date : reduce) {
                DateResult dateResult = new DateResult();
                dateResult.setDate(date);
                dateResult.setTotal(0);
                results.add(dateResult);
            }
        }
        /**根据日期排序*/
        results = results.stream().sorted(Comparator.comparing(DateResult::getDate)).collect(Collectors.toList());
        return Result.success(results);
    }


    /**
     * 运维分析-调度分析
     * @param accountId 区域id
     * @param startDate 开始时间
     * @param endDate   结束时间
     * @return  Result<List<DateResult>>
     */
    @Override
    public Result<List<DateResult>> getDispatchAnalyze(Integer accountId, Date startDate, Date endDate) {
        //获取传入时间每天的日期
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        List<String> findTimeList = DateTimeUtil.findDaysStr(simpleDateFormat.format(startDate), simpleDateFormat.format(endDate));
        //查询区域统计数据
        BarChartDispatchLogDTO barChartDispatchLogDTO = new BarChartDispatchLogDTO()
                .setAccountId(accountId)
                .setStartDate(startDate)
                .setEndDate(endDate);
        List<DateResult> result = dispatchLogDao.statisticsByTime(barChartDispatchLogDTO);
        //获取查询数据的日期集合
        List<String> dateList = result.stream().map(DateResult::getDate).collect(Collectors.toList());
        //得到传入时间和查询数据日期集合的差集
        List<String> reduce = findTimeList.stream().filter(item -> !dateList.contains(item)).collect(Collectors.toList());
        //进行补0
        if (!NullUtils.isEmpty(reduce)) {
            for (String date : reduce) {
                DateResult dateResult = new DateResult();
                dateResult.setDate(date);
                dateResult.setTotal(0);
                result.add(dateResult);
            }
        }
        /*根据日期排序*/
        return Result.success(result.stream().
                sorted(Comparator.comparing(DateResult::getDate))
                .collect(Collectors.toList()));
    }


    /**
     * 运维分析-维修分析
     * @param accountId 区域id
     * @param startDate 开始时间
     * @param endDate   结束时间
     * @return  Result<List<DateResult>>
     */
    @Override
    public Result<List<DateResult>> getRepairAnalyze(Integer accountId, Date startDate, Date endDate) {
        //获取传入时间每天的日期
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        List<String> findTimeList = DateTimeUtil.findDaysStr(simpleDateFormat.format(startDate), simpleDateFormat.format(endDate));

        BarChartRepairDTO barChartRepairDTO = new BarChartRepairDTO()
                .setAccountId(accountId)
                .setStartTime(startDate.getTime())
                .setEndTime(endDate.getTime());
        List<DateResult> result = repairLogDao.statisticsByTime(barChartRepairDTO);
        //获取查询数据的日期集合
        List<String> dateList = result.stream().map(DateResult::getDate).collect(Collectors.toList());
        //得到传入时间和查询数据日期集合的差集
        List<String> reduce = findTimeList.stream().filter(item -> !dateList.contains(item)).collect(Collectors.toList());
        //进行补0
        if (!NullUtils.isEmpty(reduce)) {
            for (String date : reduce) {
                DateResult dateResult = new DateResult();
                dateResult.setDate(date);
                dateResult.setTotal(0);
                result.add(dateResult);
            }
        }
        return Result.success(result.stream().
                sorted(Comparator.comparing(DateResult::getDate))
                .collect(Collectors.toList()));
    }


    /**
     * 运维分析-挪车分析
     * @param accountId 区域id
     * @param startDate 开始时间
     * @param endDate   结束时间
     * @return  Result<List<DateResult>>
     */
    @Override
    public Result<List<DateResult>> getMoveAnalyze(Integer accountId, Date startDate, Date endDate) {
        List<DateResult> dateResults = moveLogService.statisticsByTime(accountId, null, startDate.getTime(), endDate.getTime());
        return Result.success(dateResults);
    }


    /**
     * 处理单天的小时数据
     *
     * @param machineLineChartVOList 数据列表
     * @param hour                 小时列表
     * @param type                 数据类型
     * @param lineChartVOList      返回数据列表
     */
    private void processHourlyData(List<MachineLineChartVO> machineLineChartVOList, List<Integer> hour, Integer type, List<LineChartVO> lineChartVOList) {
        Map<String, Integer> dataMap = getDataMap(machineLineChartVOList, type);
        hour.forEach(s -> lineChartVOList.add(new LineChartVO(s.toString(), dataMap.getOrDefault(s.toString(), 0))));
    }


    /**
     * 处理多天的日期数据
     *
     * @param machineLineChartVOList 数据列表
     * @param findTimeList         日期列表
     * @param type                 数据类型
     * @param lineChartVOList      返回数据列表
     */
    private void processDailyData(List<MachineLineChartVO> machineLineChartVOList, List<String> findTimeList, Integer type, List<LineChartVO> lineChartVOList) {
        Map<String, Integer> dataMap = getDataMap(machineLineChartVOList, type);
        findTimeList.forEach(date -> lineChartVOList.add(new LineChartVO(date, dataMap.getOrDefault(date, 0))));
    }


    /**
     * 获取不同类型的数据映射
     * @param machineLineChartVOList 数据列表
     * @param type  数据类型
     * @return Map<String, Integer>
     */
    private Map<String, Integer> getDataMap(List<MachineLineChartVO> machineLineChartVOList, Integer type) {
        switch (type){
            case 1:
                return machineLineChartVOList.stream().collect(Collectors.toMap(MachineLineChartVO::getDate, MachineLineChartVO::getLowBattery));
            case 2:
                return machineLineChartVOList.stream().collect(Collectors.toMap(MachineLineChartVO::getDate, MachineLineChartVO::getOutArea));
            case 3:
                return machineLineChartVOList.stream().collect(Collectors.toMap(MachineLineChartVO::getDate, MachineLineChartVO::getOutSide));
            default:
                throw new BaseException("参数错误,不存在的type");
        }
    }



    /**
     * 判断两个时间是否在同一天
     *
     * @param beginDate 开始时间
     * @param endDate   结束江
     * @return boolean
     */
    private boolean isSameDay(Date beginDate, Date endDate) {
        LocalDate localDate1 = beginDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        LocalDate localDate2 = endDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        return localDate1.isEqual(localDate2);
    }

    /**
     * 获取指定时间内的小时集合
     *
     * @param startDate 开始时间
     * @param endDate   结束时间
     * @return List<String>
     */
    private List<Integer> getHour(Date startDate, Date endDate) {
        List<DateTime> dateTimes = DateUtil.rangeToList(startDate, endDate, DateField.HOUR_OF_DAY);
        return dateTimes.stream()
                .map(date -> Integer.parseInt(DateUtil.format(date, "HH")))
                .collect(Collectors.toList());
    }
}
